﻿using System;

namespace Cpu6502
{
    public static class MemoryHelper
    {
        /// <summary>
        /// Gets the correct memory address from the passed input and type of memory operation
        /// </summary>
        /// <param name="input"></param>
        /// <param name="addressType"></param>
        /// <returns></returns>
        public static Int16 GetAddress(Int16 input, CPU.AddressType addressType)
        {            
            if (addressType == CPU.AddressType.Absolute)
            {
                return input;
            }            
            else if (addressType == CPU.AddressType.AbsoluteIndexedX)
            {
                return (Int16)(input + CPU.Registers.X);
            }
            else if (addressType == CPU.AddressType.AbsoluteIndexedY)
            {
                return (Int16)(input + CPU.Registers.Y);
            }
            else if (addressType == CPU.AddressType.ZeroPage)
            {
                Byte page = (byte)input;
                return (Int16)(0x00 | page);
            }
            else if (addressType == CPU.AddressType.ZeroPageIndexedX)
            {
                Byte page = (byte)input;
                return (Int16)((page | 0x00) + CPU.Registers.X);
            }
            else if (addressType == CPU.AddressType.ZeroPageIndexedY)
            {
                Byte page = (byte)input;
                return (Int16)((page| 0x00) + CPU.Registers.Y);
            }
            else if (addressType == CPU.AddressType.IndexedIndirect)
            {
                Byte startAddress = (byte)(input + CPU.Registers.X);
                Byte endAddress = (byte)(startAddress + 1);
                return (Int16)((endAddress << 8) | startAddress);
            }
            else if (addressType == CPU.AddressType.IndirectIndexed)
            {
                Byte endAddress = (byte)(input + 1);
                Int16 finalAddress = (Int16)((input >> 8) | endAddress);
                return (Int16)(finalAddress + CPU.Registers.Y);
            }
            return input;
        }

        public static int RelativeAddress(int pc, Int16 address)
        {
            // Address is positive
            if (address < 0x80)
            {
                return pc + address;
            }
            else
            {
                // Negative address
                Int16 twos_compliment = (Int16)((address ^ 1111111111111111) + 1);
                return pc + twos_compliment;
            }            
        }
    }
}
